﻿using Jayrock.Json.Conversion;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;

namespace open_api_sdk_csharp.com.chinaums.open.api.internals.utils.convertors
{
    public class JsonConverter<T> : Converter<T> where T : OpenApiResponse
    {
        public static readonly Dictionary<string, Dictionary<string, OpenModel>> attrs_ = new Dictionary<string, Dictionary<string, OpenModel>>();
        public T toResponse(string paramString, Type paramClass)
        {
            T rsp = null;
            IDictionary json = JsonConvert.Import(paramString) as IDictionary;
            if (json != null)
            {
               
                    IOpenApiReader reader = new OpenApiReader(json);
                    rsp = (T)OpenApiConvert(reader, typeof(T));
            }
            if (rsp == null)
            {
                rsp = Activator.CreateInstance<T>();
            }
            return rsp;
        }

        protected static readonly DOpenApiConvert OpenApiConvert = delegate (IOpenApiReader reader, Type type)
        {
            object rsp = null;
            Dictionary<string, OpenModel> pas = GetOpenModelAttributes(type);
            Dictionary<string, OpenModel>.Enumerator em = pas.GetEnumerator();
            while (em.MoveNext())
            {
                KeyValuePair<string, OpenModel> kvp = em.Current;
                OpenModel openModel = kvp.Value;
                string itemName = openModel.ItemName;
                if (!reader.HasReturnField(itemName))
                {
                    continue;
                }
                object value = null;
                if (typeof(string) == openModel.ItemType)
                {
                    object tmp = reader.GetPrimitiveObject(itemName);
                    if (tmp != null)
                    {
                        value = tmp.ToString();
                    }
                }
                else if (typeof(long) == openModel.ItemType)
                {
                    object tmp = reader.GetPrimitiveObject(itemName);
                    if (tmp != null)
                    {
                        value = ((IConvertible)tmp).ToInt64(null);
                    }
                }
                else if (typeof(int) == openModel.ItemType)
                {
                    object tmp = reader.GetPrimitiveObject(itemName);
                    if (tmp != null)
                    {
                        value = ((IConvertible)tmp).ToInt32(null);
                    }
                }
                else if (typeof(bool) == openModel.ItemType)
                {
                    value = reader.GetPrimitiveObject(itemName);
                }
                else if (typeof(object) == openModel.ItemType)
                {
                    object tmp = reader.GetPrimitiveObject(itemName);
                    if (tmp != null)
                    {
                        value = tmp.ToString();
                    }
                }
                else
                {
                    value = reader.GetReferenceObject(itemName, openModel.ItemType, OpenApiConvert);
                }

                if (value != null)
                {
                    if (rsp == null)
                    {
                        rsp = Activator.CreateInstance(type);
                    }
                    openModel.Method.Invoke(rsp, new object[] { value });
                }
            }
            return rsp;
        };
        private static Dictionary<string, OpenModel> GetOpenModelAttributes(Type type)
        {
            Dictionary<String, OpenModel> dict = null;
            bool isExsits = attrs_.TryGetValue(type.FullName, out dict);
            if (isExsits && dict != null)
            {
                return dict;
            }
            else
            {
                dict = new Dictionary<string, OpenModel>();
            }
            PropertyInfo[] pis = type.GetProperties();
            foreach (PropertyInfo pi in pis)
            {
                OpenModel openModel = new OpenModel();
                openModel.Method = pi.SetMethod;
                openModel.ItemName = pi.Name;
                openModel.ItemType = pi.PropertyType;
                dict.Add(pi.Name + openModel.ItemType, openModel);
            }
            attrs_[type.FullName] = dict;
            return dict;
        }
    }
}
